home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d13 / patch12.arc / POPEN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-02  |  10.3 KB  |  340 lines

  1. /* popen/pclose:
  2.  *
  3.  * simple MS-DOS piping scheme to imitate UNIX pipes
  4.  *
  5.  * $Log:    popen.c,v $
  6.  * Revision 1.0.1  90/07/15  14:05:00  aas
  7.  * fix assumption of trailing "/" in popen()
  8.  *
  9.  * Revision 1.0.0  88/08/03  20:08:00  ???
  10.  * original distribution: author unknown
  11.  * found on simtel20 as pd1:<msdos.turbo-c>popen.arc
  12.  *
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <alloc.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <setjmp.h>
  21. #include <process.h>
  22.  
  23. #include "popen.h"
  24.  
  25. extern char *getenv( char * );
  26.  
  27. #ifndef    _NFILE
  28. # define    _NFILE    OPEN_MAX    /* Number of open files */
  29. #endif    _NFILE
  30.  
  31. #define READIT    1            /* Read pipe */
  32. #define WRITEIT    2            /* Write pipe */
  33.  
  34. static char *prgname[ _NFILE ];        /* program name if write pipe */
  35. static int pipetype[ _NFILE ];        /* 1=read 2=write */
  36. static char *pipename[ _NFILE ];    /* pipe file name */
  37.  
  38. /*
  39.  *------------------------------------------------------------------------
  40.  * stoupper: Convert string to uppercase (in place)
  41.  *------------------------------------------------------------------------
  42.  */
  43.  
  44. static void
  45. stoupper( s )
  46. char *s;
  47. {
  48.    int c;
  49.    for( ; (c = *s) != '\0'; ++s ) {
  50.       if( islower( c ) ) *s = _toupper( c );
  51.    }
  52. }
  53.  
  54. /*
  55.  *------------------------------------------------------------------------
  56.  * strsave: Copy string into malloc'ed memory and return address
  57.  *------------------------------------------------------------------------
  58.  */
  59.  
  60. static char *
  61. strsave( s )
  62. char *s;
  63. {
  64.    char *sp = malloc( strlen( s ) + 1 );
  65.    if( sp != (char *) NULL ) (void) strcpy( sp, s );
  66.    return( sp );
  67. }
  68.  
  69. /*
  70.  *------------------------------------------------------------------------
  71.  * strfree: Returm strsave'd string memory
  72.  *------------------------------------------------------------------------
  73.  */
  74.  
  75. static void
  76. strfree( s )
  77. char *s;
  78. {
  79.    if( s != (char *) NULL ) free( s );
  80. }
  81.  
  82. /*
  83.  *------------------------------------------------------------------------
  84.  * run: Execute command via SHELL or COMSPEC
  85.  *------------------------------------------------------------------------
  86.  */
  87.  
  88. static int
  89. run( command )
  90. char *command;
  91. {
  92.    jmp_buf panic;            /* How to recover from errors */
  93.    int lineno;                /* Line number where panic happened */
  94.    char *shell;                /* Command processor */
  95.    char *s = (char *) NULL;        /* Holds the command */
  96.    int s_is_malloced = 0;        /* True if need to free 's' */
  97.    static char *command_com = "COMMAND.COM";
  98.    int status;                /* Return codes */
  99.    char *shellpath;            /* Full command processor path */
  100.    char *bp;                /* Generic string pointer */
  101.    static char dash_c[ 3 ] = { '?', 'c', '\0' };
  102.    if( (lineno = setjmp( panic )) != 0 ) {
  103.       int E = errno;
  104. #ifdef    DEMO
  105.       fprintf( stderr, "RUN panic on line %d: %d\n", lineno, E );
  106. #endif    DEMO
  107.       if( s_is_malloced && (s != (char *) NULL) ) strfree( s );
  108.       errno = E;
  109.       return( -1 );
  110.    }
  111.    if( (s = strsave( command )) == (char *) NULL ) longjmp( panic, __LINE__ );
  112.    /* Determine the command processor */
  113.    if( ((shell = getenv( "SHELL" )) == (char *) NULL) &&
  114.        ((shell = getenv( "COMSPEC" )) == (char *) NULL) ) shell = command_com;
  115.    stoupper( shell );
  116.    shellpath = shell;
  117.    /* Strip off any leading backslash directories */
  118.    shell = strrchr( shellpath, '\\' );
  119.    if( shell != (char *) NULL ) ++shell;
  120.    else                         shell = shellpath;
  121.    /* Strip off any leading slash directories */
  122.    bp = strrchr( shell, '/'  );
  123.    if( bp != (char *) NULL ) shell = ++bp;
  124.    if( strcmp( shell, command_com ) != 0 ) {
  125.       /* MKS Shell needs quoted argument */
  126.       char *bp;
  127.       if( (bp = s = malloc( strlen( command ) + 3 )) == (char *) NULL ) 
  128.      longjmp( panic, __LINE__ );
  129.       *bp++ = '\'';
  130.       while( (*bp++ = *command++) != '\0' );
  131.       *(bp - 1) = '\'';
  132.       *bp = '\0';
  133.       s_is_malloced = 1;
  134.    } else s = command;
  135.    dash_c[ 0 ] = getswitch();
  136.    /* Run the program */
  137. #ifdef    DEMO
  138.    fprintf( stderr, "Running: (%s) %s %s %s\n", shellpath, shell, dash_c, s );
  139. #endif    DEMO
  140.    status = spawnl( P_WAIT, shellpath, shell, dash_c, s, (char *) NULL );
  141.    if( s_is_malloced ) free( s );
  142.    return( status );
  143. }
  144.  
  145. /* 
  146.  *------------------------------------------------------------------------
  147.  * uniquepipe: returns a unique file name 
  148.  *------------------------------------------------------------------------
  149.  */
  150.  
  151. static char *
  152. uniquepipe()
  153.    static char name[ 14 ];
  154.    static short int num = 0;
  155.    (void) sprintf( name, "pipe%04d.tmp", num++ );
  156.    return( name );
  157. }
  158.  
  159. /*
  160.  *------------------------------------------------------------------------
  161.  * resetpipe: Private routine to cancel a pipe
  162.  *------------------------------------------------------------------------
  163.  */
  164.  
  165. static void
  166. resetpipe( fd )
  167. int fd;
  168. {
  169.    char *bp;
  170.    if( (fd >= 0) && (fd < _NFILE) ) {
  171.       pipetype[ fd ] = 0;
  172.       if( (bp = pipename[ fd ]) != (char *) NULL ) {
  173.      (void) unlink( bp );
  174.      strfree( bp );
  175.      pipename[ fd ] = (char *) NULL;
  176.       }
  177.       if( (bp = prgname[ fd ]) != (char *) NULL ) {
  178.      strfree( bp );
  179.      prgname[ fd ] = (char *) NULL;
  180.       }
  181.    }
  182. }
  183.  
  184. /* 
  185.  *------------------------------------------------------------------------
  186.  * popen: open a pipe 
  187.  *------------------------------------------------------------------------
  188.  */
  189.  
  190. FILE *popen( prg, type )
  191. char *prg;            /* The command to be run */
  192. char *type;            /* "w" or "r" */
  193.    FILE *p = (FILE *) NULL;    /* Where we open the pipe */
  194.    int ostdin;            /* Where our stdin is now */
  195.    int pipefd = -1;        /* fileno( p ) -- for convenience */
  196.    char tmpfile[ BUFSIZ ];    /* Holds name of pipe file */
  197.    char *tmpdir;        /* Points to directory prefix of pipe */
  198.    jmp_buf panic;        /* Where to go if there's an error */
  199.    int lineno;            /* Line number where panic happened */
  200.    char c;                            /* aas */
  201.    /* Find out where we should put temporary files */
  202.    if( (tmpdir = getenv( "TMPDIR" )) == (char *) NULL ) 
  203.       tmpdir = getenv( "TMP" );
  204.    if( tmpdir != (char *) NULL ) {
  205.       /* Use temporary directory if available */
  206.       (void) strcpy( tmpfile, tmpdir );
  207.       if((c=tmpfile[strlen(tmpfile)-1])!='/' && c!='\\')    /* aas */
  208.      (void) strcat( tmpfile, "/" );
  209.    } else *tmpfile = '\0';
  210.    /* Get a unique pipe file name */
  211.    (void) strcat( tmpfile, uniquepipe() );
  212.    if( (lineno = setjmp( panic )) != 0 ) {
  213.       /* An error has occurred, so clean up */
  214.       int E = errno;
  215. #ifdef    DEMO
  216.       fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
  217. #endif    DEMO
  218.       if( p != (FILE *) NULL ) (void) fclose( p );
  219.       resetpipe( pipefd );
  220.       errno = E;
  221.       return( (FILE *) NULL );
  222.    }
  223.    if( strcmp( type, "w" ) == 0 ) {
  224.       /* for write style pipe, pclose handles program execution */
  225.       if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
  226.      pipefd = fileno( p );
  227.      pipetype[ pipefd ] = WRITEIT;
  228.      pipename[ pipefd ] = strsave( tmpfile );
  229.      prgname[ pipefd ]  = strsave( prg );
  230.      if( !pipename[ pipefd ] || !prgname[ pipefd ] ) longjmp( panic, __LINE__ );
  231.       }
  232.    } else if( strcmp( type, "r" ) == 0 ) {
  233.       /* read pipe must create tmp file, set up stdout to point to the temp
  234.       * file, and run the program.  note that if the pipe file cannot be
  235.       * opened, it'll return a condition indicating pipe failure, which is
  236.       * fine.
  237.       */
  238.       if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
  239.      int ostdout;
  240.      pipefd = fileno( p );
  241.      pipetype[ pipefd ]= READIT;
  242.      if( (pipename[ pipefd ] = strsave( tmpfile )) == (char *) NULL ) 
  243.         longjmp( panic, __LINE__ );
  244.      /* Redirect stdin for the new command */
  245.      ostdout = dup( fileno( stdout ) );
  246.      if( dup2( fileno( stdout ), pipefd ) < 0 ) {
  247.         int E = errno;
  248.         (void) dup2( fileno( stdout ), ostdout );
  249.         errno = E;
  250.         longjmp( panic, __LINE__ );
  251.      }
  252.      if( run( prg ) != 0 ) longjmp( panic, __LINE__ );
  253.      if( dup2( fileno( stdout ), ostdout ) < 0 ) longjmp( panic, __LINE__ );
  254.      if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
  255.      if( (p = fopen( tmpfile, "r" )) == (FILE *) NULL ) longjmp( panic, __LINE__ );
  256.       }
  257.    } else {
  258.       /* screwy call or unsupported type */
  259.       errno = EINVFNC;
  260.       longjmp( panic, __LINE__ );
  261.    }
  262.    return( p );
  263. }
  264.  
  265. /* close a pipe */
  266.  
  267. int
  268. pclose( p )
  269. FILE *p;
  270. {
  271.    int pipefd = -1;        /* Fildes where pipe is opened */
  272.    int ostdout;            /* Where our stdout points now */
  273.    int ostdin;            /* Where our stdin points now */
  274.    jmp_buf panic;        /* Context to return to if error */
  275.    int lineno;            /* Line number where panic happened */
  276.    if( (lineno = setjmp( panic )) != 0 ) {
  277.       /* An error has occurred, so clean up and return */
  278.       int E = errno;
  279. #ifdef    DEMO
  280.       fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
  281. #endif    DEMO
  282.       if( p != (FILE *) NULL ) (void) fclose( p );
  283.       resetpipe( pipefd );
  284.       errno = E;
  285.       return( -1 );
  286.    }
  287.    pipefd = fileno( p );
  288.    if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
  289.    switch( pipetype[ pipefd ] ) {
  290.       case WRITEIT:
  291.      /* open the temp file again as read, redirect stdin from that
  292.       * file, run the program, then clean up.
  293.       */
  294.       if( (p = fopen( pipename[ pipefd ],"r" )) == (FILE *) NULL ) 
  295.      longjmp( panic, __LINE__ );
  296.       ostdin = dup( fileno( stdin ));
  297.       if( dup2( fileno( stdin ), fileno( p ) ) < 0 ) longjmp( panic, __LINE__ );
  298.       if( run( prgname[ pipefd ] ) != 0 ) longjmp( panic, __LINE__ );
  299.       if( dup2( fileno( stdin ), ostdin ) < 0 ) longjmp( panic, __LINE__ );
  300.       if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
  301.       resetpipe( pipefd );
  302.       break;
  303.    case READIT:
  304.       /* close the temp file and remove it */
  305.       resetpipe( pipefd );
  306.       break;
  307.    default:
  308.       errno = EINVFNC;
  309.       longjmp( panic, __LINE__ );
  310.       /*NOTREACHED*/
  311.    }
  312.    return( 0 );
  313. }
  314.  
  315. #ifdef    DEMO
  316. int
  317. main( argc, argv )
  318. int argc;
  319. char **argv;
  320. {
  321.    FILE *pipe;
  322.    char buf[ BUFSIZ ];
  323.    int n;
  324.    *buf = '\0';
  325.    for( n = 1; n < argc; ++n ) {
  326.       (void) strcat( buf, argv[ n ] );
  327.       (void) strcat( buf, " " );
  328.    }
  329.    if( (pipe = popen( buf, "r" )) != (FILE *) NULL ) {
  330.       while( fgets( buf, sizeof( buf ), pipe ) != (char *) NULL ) 
  331.      (void) fputs( buf, stdout );
  332.       if( pclose( pipe ) != 0 ) fprintf( stderr, "error closing pipe!\n" );
  333.    } else fprintf( stderr, "it didn't work!\n" );
  334.    exit( 0 );
  335.    /*NOTREACHED*/
  336. }
  337. #endif    DEMO
  338.